﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using OpenCvApplication.View.CommonView;

namespace OpenCvApplication.View
{
    public partial class FrmBT : FrmBase
    {
        public FrmBT()
        {
            InitializeComponent();




        }
        public string ImageExtension { get; private set; }
        public string[] ImageExtensions { get; } = { ".bmp", ".jpg", ".jpeg", ".png" };
        string path;
        /// <summary>
        /// 选择图像
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            using OpenFileDialog openFileDialog = new OpenFileDialog();
            if (string.IsNullOrEmpty(ImageExtension))
            {
                string temp = String.Join(";", ImageExtensions.Select(t => $"*{t}"));
                ImageExtension = $"Image Files ({temp})|{temp}";
            }
            openFileDialog.Filter = ImageExtension;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string selectedFile = openFileDialog.FileName;
                path = selectedFile;
                this.pictureBox1.Image?.Dispose();
                this.pictureBox1.Image = new Bitmap(path);
                img?.Dispose();
                img = new Image<Bgra, byte>(path);

                imgShow?.Dispose();
                gray?.Dispose();
            }
        }
        /// <summary>
        /// 计算中点像素大小
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public double CalculateMedian(Image<Gray, byte> image)
        {
            byte[] bytes = image.Bytes;
            Array.Sort(bytes);
            double median = bytes[bytes.Length >> 1];
            return median;
        }
        public double CalculateAvg(Image<Gray, byte> image)
        {
            byte[] array = image.Bytes;
            int count = array.Length;
            unsafe
            {
                int sum = 0;

                fixed (byte* p = array)
                {
                    for (int i = 0; i < count; i++)
                    {
                        sum += *(p + i);
                    }
                }

                return sum / (double)count;
            }
        }
        private Point RectStartPoint;
        private Rectangle Rect = new Rectangle();
        private Brush selectionBrush = new SolidBrush(Color.FromArgb(128, 72, 145, 220));
        Image<Bgra, byte> img;
        Image<Bgra, byte> imgShow;
        Image<Gray, byte> gray;
        /// <summary>
        /// 生成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            if (pictureBox1.Image == null)
            {
                MessageBox.Show("请选择图片");
                return;
            }
            img?.Dispose();
            img = new Image<Bgra, byte>(new Bitmap(pictureBox1.Image));



            // 加载图像
            //using Image<Bgr, byte> image = img.Convert<Bgr, byte>();
            // 创建掩码
            //using Image<Gray, byte> mask = new Image<Gray, byte>(image.Width, image.Height, new Gray(0));
            // 创建矩形来指定前景区域（文字区域）
            //Rectangle rectangle = new Rectangle(50, 50, 200, 200);
            // 创建背景模型和前景模型
            //using Mat bgdModel = new Mat();
            //using Mat fgdModel = new Mat();
            // 运行GrabCut算法
            //CvInvoke.GrabCut(image, mask, rectangle, bgdModel, fgdModel, 5, GrabcutInitType.InitWithRect);
            // 将掩码中的可能前景和确定前景区域设为白色，其他区域设为黑色
            //CvInvoke.Threshold(mask, mask, 2, 255, ThresholdType.Binary);
            // 提取前景（文字）
            //using Image<Bgr, byte> foreground = image.Copy(mask);




            //// 掩码
            using Image<Gray, byte> mask2 = img.InRange(new Bgra(trackBar5.Value, trackBar4.Value, trackBar3.Value, 0), new Bgra(255, 255, 255, 255));

            //// 将掩码中选取的颜色的alpha通道设置为0
            img.SetValue(new Bgra(0, 0, 0, 0), mask2);


            this.pictureBox2.Image?.Dispose();
            this.pictureBox2.Image = img.Bitmap;
        }
        /// <summary>
        /// 自动适配
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            if (pictureBox1.Image == null)
            {
                MessageBox.Show("请选择图像");
                return;
            }
            imgShow?.Dispose();
            gray?.Dispose();

            imgShow = new Image<Bgra, byte>(new Bitmap(pictureBox1.Image));
            gray = imgShow.Convert<Gray, byte>();


            // 高斯滤波
            using Mat filteredImage = new Mat();
            //var best = GetBestGaussianBlur(gray);
            //CvInvoke.GaussianBlur(gray, filteredImage, new Size(best.KZize, best.KZize), best.SigmaX, best.SigmaY);
            CvInvoke.GaussianBlur(gray, filteredImage, new Size(9, 9), 0);
            gray = filteredImage.ToImage<Gray, byte>();

            double median = radioButton1.Checked ? CalculateMedian(gray) : CalculateAvg(gray);

            double sigma = (float)numericUpDown1.Value;
            double lower = Math.Max(0, (1.0 - sigma) * median);
            double upper = Math.Min(255, (1.0 + sigma) * median);
            trackBar1.Value = (int)lower;
            label1.Text = trackBar1.Value.ToString();
            trackBar2.Value = (int)upper;
            label3.Text = trackBar2.Value.ToString();
        }
        const int minKSize = 3;
        const int maxKSize = 21;
        const int stepSize = 2;
        const double minSigmaX = 0;
        const double maxSigmaX = 50;
        const double minSigmaY = 0;
        const double maxSigmaY = 50;
        object lockObj = new object(); // 用于保护共享变量的锁
        private (int KZize, double SigmaX, double SigmaY) GetBestGaussianBlur(Image<Gray, byte> gray)
        {
            double bestEvaluation = double.MinValue;
            int bestKSize = 0;
            double bestSigmaX = 0.0;
            double bestSigmaY = 0.0;
            //Image<Gray, byte> input = null;

            var results = new ConcurrentDictionary<double, (int KSize, double SigmaX, double SigmaY)>();

            Parallel.For(minKSize, maxKSize, ksize =>
            {
                if ((ksize & 1) == 0)
                    return;

                try
                {
                    for (double sigmaX = minSigmaX; sigmaX <= maxSigmaX; sigmaX += stepSize)
                    {
                        for (double sigmaY = minSigmaY; sigmaY <= maxSigmaY; sigmaY += stepSize)
                        {
                            // 应用高斯滤波
                            Image<Gray, byte> input = gray.Copy();
                            CvInvoke.GaussianBlur(gray, input, new Size(ksize, ksize), sigmaX, sigmaY);

                            using var tempImg = input.Convert<Bgr, byte>();

                            try
                            {
                                // 计算评估指标
                                double evaluation = ComputeEvaluationMetric(tempImg.Mat);

                                // 存储计算结果
                                results.TryAdd(evaluation, (ksize, sigmaX, sigmaY));
                            }
                            catch
                            {
                                break;
                            }
                            finally
                            {
                                input.Dispose();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {

                }
            });

            // 找到最佳参数组合
            foreach (var result in results.OrderByDescending(r => r.Key))
            {
                if (result.Key > bestEvaluation)
                {
                    bestEvaluation = result.Key;
                    bestKSize = result.Value.KSize;
                    bestSigmaX = result.Value.SigmaX;
                    bestSigmaY = result.Value.SigmaY;
                }
            }

            //for (int ksize = minKSize; ksize <= maxKSize; ksize += stepSize)
            //{
            //    for (double sigmaX = minSigmaX; sigmaX <= maxSigmaX; sigmaX += stepSize)
            //    {
            //        for (double sigmaY = minSigmaY; sigmaY <= maxSigmaY; sigmaY += stepSize)
            //        {
            //            // 应用高斯滤波
            //            CvInvoke.GaussianBlur(gray, input, new Size(ksize, ksize), sigmaX, sigmaY);

            //            using var tempImg = input.Convert<Bgr, byte>();
            //            try
            //            {
            //                // 计算评估指标
            //                double evaluation = ComputeEvaluationMetric(tempImg.Mat);

            //                // 更新最佳参数组合
            //                if (evaluation > bestEvaluation)
            //                {
            //                    bestEvaluation = evaluation;
            //                    bestKSize = ksize;
            //                    bestSigmaX = sigmaX;
            //                    bestSigmaY = sigmaY;
            //                }
            //            }
            //            catch
            //            {
            //                break;
            //            }
            //            finally
            //            {
            //                input?.Dispose();
            //            }
            //        }
            //    }
            //}

            return (bestKSize, bestSigmaX, bestSigmaY);
        }
        /// <summary>
        /// 计算评估指标
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        private double ComputeEvaluationMetric(Mat image)
        {
            // 将图像转换为灰度图像（如果需要）
            using Mat grayImage = new Mat();
            CvInvoke.CvtColor(image, grayImage, ColorConversion.Bgr2Gray);

            // 计算图像的梯度
            using Mat gradientX = new Mat();
            using Mat gradientY = new Mat();
            CvInvoke.Sobel(grayImage, gradientX, DepthType.Cv64F, 1, 0);
            CvInvoke.Sobel(grayImage, gradientY, DepthType.Cv64F, 0, 1);

            // 创建梯度幅值和梯度角度的输出数组
            Mat gradientMagnitude = new Mat();
            Mat gradientAngle = new Mat();

            // 计算梯度的幅值和角度
            CvInvoke.CartToPolar(gradientX, gradientY, gradientMagnitude, gradientAngle, true);

            // 计算梯度幅值的均值
            MCvScalar meanScalar = CvInvoke.Mean(gradientMagnitude);
            double meanMagnitude = meanScalar.V0;

            return meanMagnitude;
        }


        /// <summary>
        /// Canny生成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button6_Click(object sender, EventArgs e)
        {
            if (gray == null || imgShow == null)
            {
                MessageBox.Show("请先选择自动适配");
                return;
            }
            // Canny算子边缘检测
            using Image<Gray, byte> edges = gray.Canny(trackBar1.Value, trackBar2.Value);
            using VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
            using Mat hier = new Mat();

            CvInvoke.FindContours(edges, contours, hier, RetrType.List, ChainApproxMethod.ChainApproxSimple);
            // 掩码
            using Image<Gray, byte> mask = new Image<Gray, byte>(gray.Size);
            if (contours.Size > 10000)
            {
                MessageBox.Show("边缘太多，会非常耗时，请重先调节参数");
                return;
            }
            // 在imgShow图像上填充边缘边框
            for (int i = 0; i < contours.Size; i++)
            {
                var contour = contours[i];
                CvInvoke.DrawContours(imgShow, contours, i, new MCvScalar(0, 0, 255), 2);
                CvInvoke.DrawContours(mask, contours, i, new MCvScalar(255), thickness: -1);
            }
            this.pictureBox3.Image?.Dispose();
            this.pictureBox3.Image = imgShow.Bitmap;

            using Image<Gray, byte> maskedImage = new Image<Gray, byte>(gray.Size);
            // 使用掩码进行位与操作
            CvInvoke.BitwiseAnd(gray, gray, maskedImage, mask);

            // 计算平均值
            MCvScalar average = CvInvoke.Mean(maskedImage, mask);


            double blue = average.V0;
            double green = average.V1;
            double red = average.V2;
            trackBar3.Value = (int)Math.Round(red, 0);
            trackBar4.Value = (int)Math.Round(green, 0);
            trackBar5.Value = (int)Math.Round(blue, 0);
            label9.Text = trackBar3.Value.ToString();
            label10.Text = trackBar4.Value.ToString();
            label12.Text = trackBar5.Value.ToString();
        }
        private void FrmBT_FormClosing(object sender, FormClosingEventArgs e)
        {
            gray?.Dispose();
            imgShow?.Dispose();
            selectionBrush.Dispose();
            img?.Dispose();
            foreach (Control item in this.Controls)
            {
                if (item is PictureBox pictureBox)
                {
                    pictureBox.Image?.Dispose();
                    pictureBox?.Dispose();
                }
            }
            this.Dispose();
            GC.Collect();
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            label1.Text = trackBar1.Value.ToString();
        }
        /// <summary>
        /// 双击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            if (img == null)
            {
                MessageBox.Show("请先生成图片");
                return;
            }

            using (FrmBTImageProcessing fb = new FrmBTImageProcessing(img, path))
            {
                fb.ShowDialog();
            }
        }

        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            label3.Text = trackBar2.Value.ToString();
        }
        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            if (img == null)
            {
                MessageBox.Show("请先生成图像");
                return;
            }
            var spath = Path.GetDirectoryName(path);
            img.Save(Path.Combine(spath, $"{DateTime.Now.ToString("yyyyMMddHHmmss")}Output.png"));
            MessageBox.Show("生成成功");
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            label7.Text = numericUpDown1.Value.ToString();
        }

        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            label9.Text = trackBar3.Value.ToString();
        }

        private void trackBar4_Scroll(object sender, EventArgs e)
        {
            label10.Text = trackBar4.Value.ToString();
        }

        private void trackBar5_Scroll(object sender, EventArgs e)
        {
            label12.Text = trackBar5.Value.ToString();
        }
        /// <summary>
        /// 手写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            using (FrmInput fin = new FrmInput())
            {
                fin.Signature = SignatureShow;
                fin.ShowDialog();
            }
        }
        private void SignatureShow(Image image)
        {
            img?.Dispose();
            imgShow?.Dispose();
            gray?.Dispose();
            this.pictureBox1.Image?.Dispose();
            this.pictureBox1.Image = image;
        }
        /// <summary>
        /// 新算法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button7_Click(object sender, EventArgs e)
        {
            FrmGrabCut fg=new FrmGrabCut();
            fg.Show();
        }
    }
}
